package com.dyp.security_demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.filter.DelegatingFilterProxy;

@Configuration
@EnableWebSecurity
/**
 * prePostEnabled属性决定Spring Security在接口前注解是否可用@PreAuthorize,@PostAuthorize等注解,设置为true,会拦截加了这些注解的接口
 * Determines if Spring Security's PreAuthorize, PostAuthorize, PreFilter, and PostFilter
 **/
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled=true)
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        /**
         * CSRF 防护：Spring Security 默认对所有非 GET/HEAD/OPTIONS/TRACE 的请求要求验证 CSRF Token。
         * 所以未豁免 CSRF 检查的情况下，虽然 .permitAll() 放行了路径，但依旧会报403无权限返回。
         */
        http
                .csrf(csrf -> csrf
                        .ignoringRequestMatchers("/v1/**", "/v2/**" ) // 忽略指定路径
                )
                .formLogin(Customizer.withDefaults())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/v1/all").permitAll()
                        .requestMatchers( "/v1/user/role").hasRole("USER")
                        .requestMatchers("/v1/admin/role").hasRole("ADMIN")
                        .anyRequest().authenticated()
                );

        return http.build();
    }

    /**
     * 用户信息服务(配置用户账号、密码、角色)
     * @param passwordEncoder 密码加密器
     * @return 在内存用户详细信息管理器中
     */
    @Bean
    public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {
        UserDetails user = User.withUsername("user")
                .password(passwordEncoder.encode("123456"))
                .roles("USER")
                .build();

        UserDetails admin = User.withUsername("admin")
                .password(passwordEncoder.encode("123456"))
                .roles("USER", "ADMIN")
                .build();

        return new InMemoryUserDetailsManager(user, admin);
    }

    /**
     * 密码加密器  配置了InMemoryUserDetailsManager需要配置。
     * 如果不配置提示：Consider defining a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' in your configuration.
     * @return 密码加密器的实例
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        return encoder;
    }
}